#include <twit/resource/twit4c/TwitJsonParser.h>
#include <twit/response.h>
#include <json/json.h>
#include <twit/Util.h>
using namespace Twit;

class CTwitJsonParser
{
	#define ArrayIndex Json::Value::ArrayIndex
	Json::Value root;
public:
	Twit::Error error;

	inline JsonValueRef parse(const std::string& src, Json::Value& root)
	{
		error.set(rc_ok, "");
		root.clear();

		Json::Reader reader;
		if(!reader.parse(src, root, false))
		{	
			error.set(rc_parsing_error, reader.getFormatedErrorMessages());
			return NULL;
		}

		if(root.isObject())
		{
			ArrayIndex nSize = root.size();
			if(nSize==2 && root.isMember("error") && root.isMember("request"))
			{
				error.set(rc_twitter_error, root["error"].asString());
				return NULL;
			}
			else if(nSize==1 && root.isMember("errors"))
			{
				Json::Value& e = root["errors"];
				if(e.isArray())
				{
					int eCode = (int)e[(ArrayIndex)0]["code"].asUInt();
					error.set(rc_twitter_error, "[" + Util::toString(eCode) +"] "+e[(ArrayIndex)0]["getMessage"].asString());
				}
				else
				{
					error.set(rc_twitter_error, root["errors"].asString());
				}            
				return NULL;
			}
		}
		return (JsonValueRef)&root;
	}
	inline JsonValueRef parse(const std::string& src)
	{
		return parse(src, root);
	}

	inline BOOL parseError(const std::string& errMsg)
	{
		try
		{
			parse(errMsg);
			return FALSE;
		}
		catch(...)
		{
			return TRUE;
		}
		return FALSE;
	}

	inline size_t size()
	{
		return (size_t)root.size();
	}
};

TwitJsonParser TJP_create()
{
	return (TwitJsonParser)(new CTwitJsonParser);
}

void TJP_destroy(TwitJsonParser* p)
{
	if(p && *p)
	{
		delete (CTwitJsonParser*)*p;
		*p = NULL;
	}
}

JsonValueRef TJP_parse(TwitJsonParser h, const char* source)
{
	CTwitJsonParser* p = (CTwitJsonParser*)h;
	return p->parse(std::string(source?source:""));
}

int TJP_getErrorCode(TwitJsonParser h)
{
	return ((CTwitJsonParser*)h)->error.getCode();
}
const char* TJP_getErrorMessage(TwitJsonParser h)
{
	return ((CTwitJsonParser*)h)->error.getMessage().c_str();
}

BOOL TJP_parseError(TwitJsonParser h, const char* errMsg)
{
	return ((CTwitJsonParser*)h)->parseError(std::string(errMsg?errMsg:""));
}

size_t TJP_getArraySize(JsonValueRef r)
{
	return (*((Json::Value*)r)).size();
}

JsonValueRef TJP_getValueByName(JsonValueRef r, const char* name)
{
	Json::Value* p = &((*((Json::Value*)r))[name]);
	return p->isNull() ? NULL:p;
}

JsonValueRef TJP_getValueByIndex(JsonValueRef r, const size_t index)
{
	Json::Value* p = &((*((Json::Value*)r))[index]);
	return p->isNull() ? NULL:p;
}

double TJP_valueAsDouble(JsonValueRef r)
{
	return (*((Json::Value*)r)).asDouble();
}

int TJP_valueAsInt(JsonValueRef r)
{
	return (int)(*((Json::Value*)r)).asInt();
}

const char* TJP_valueAsString(JsonValueRef r)
{
	return (*((Json::Value*)r)).asCString();
}

BOOL TJP_valueIsString(JsonValueRef r)
{
	return (*((Json::Value*)r)).isString() ? 1:0;
}

BOOL TJP_valueIsArray(JsonValueRef r)
{
	return (*((Json::Value*)r)).isArray() ? 1:0;
}

BOOL TJP_valueIsObject(JsonValueRef r)
{
	return (*((Json::Value*)r)).isObject() ? 1:0;
}

BOOL TJP_isExists(JsonValueRef r, const char* name)
{
	if(!name)	return 0;
	return (*((Json::Value*)r)).isMember(name) ? 1:0;
}

HMembers TJP_getMembers(JsonValueRef r, size_t* pSize)
{
	Json::Value::Members* p = new Json::Value::Members;
	*p = (*((Json::Value*)r)).getMemberNames();

	if(pSize) *pSize = p->size();
	if( p->size()==0)
	{
		delete p;
		p = NULL;
	}
	return (HMembers)p;
}

const char* TJP_getMemberNameByIndex(HMembers h, size_t index)
{
	if(h)
	{
		return (*((Json::Value::Members*)h))[index].c_str();
	}
	return NULL;
}

void TJP_freeMembers(HMembers* pH)
{
	if(pH && *pH)
	{
		Json::Value::Members* p = (Json::Value::Members*)*pH;
		delete p;
		*pH = NULL;
	}
}

